/**
 * @file   MainWindow.cpp
 * @author Djuro Drljaca (djurodrljaca@gmail.com)
 * @date   2013-05-03
 * @brief  DataBus Server Test Application Main Window.
 *
 * Copyright (C) 2013  Djuro Drljaca <djurodrljaca@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QtNetwork/QHostAddress>
#include <QtNetwork/QHostInfo>
#include <DataBus/Common/GetClientListRequestPacket.h>
#include <DataBus/Common/GetClientListResponsePacket.h>
#include <DataBus/Common/GetClientNameRequestPacket.h>
#include <DataBus/Common/GetClientNameResponsePacket.h>
#include <DataBus/Common/GetClientStatusResponsePacket.h>
#include <DataBus/Common/GetClientPropertyListResponsePacket.h>
#include <DataBus/Common/GetClientPropertyInfoResponsePacket.h>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent),
      ui(new Ui::MainWindow),
      m_dataBusClient(this),
      m_registeredClientIdListModel(this),
      m_selectedClientId(0),
      m_selectedClientName(),
      m_selectedClientStatus(DataBus::ClientStatus_ErrorUnknownClient),
      m_pendingPropertyIdList(),
      m_selectedClientPropertyList()
{
    // Setup GUI
    ui->setupUi(this);

    // Set Registered Clients list view model
    ui->registeredClients_listView->setModel(&m_registeredClientIdListModel);

    // Connect client's registered signal
    connect(&m_dataBusClient, SIGNAL(registered(bool)),
            this, SLOT(clientRegistered(bool)));

    // Connect client's stopped signal
    connect(&m_dataBusClient, SIGNAL(stopped()),
            this, SLOT(clientStopped()));

    // Connect client's new packet received signal
    connect(&m_dataBusClient, SIGNAL(packetReceived(DataBus::Packet)),
            this, SLOT(processReceivedPacket(DataBus::Packet)));

            // Trigger reading client list
            connect(ui->getClientList_pushButton, SIGNAL(clicked()),
                    this, SLOT(readClientList()));

    // Trigger reading client info
    connect(ui->getClientInfo_pushButton, SIGNAL(clicked()),
            this, SLOT(readClientInfo()));

    // Connect Start Server and Stop Server buttons to DataBus Server
    connect(ui->startClient_pushButton, SIGNAL(clicked()),
            this, SLOT(startClient()));

    connect(ui->stopClient_pushButton, SIGNAL(clicked()),
            this, SLOT(stopClient()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::startClient()
{
    quint8 clientId(ui->clientId_spinBox->value());
    QString clientName(ui->clientName_lineEdit->text());

    quint8 activityTimeout(ui->activityTimeout_spinBox->value());
    quint8 pingResponseTimeout(ui->pingResponseTimeout_spinBox->value());
    quint8 pingRetryCount(ui->pingRetryCount_spinBox->value());

    QHostInfo hostInfo = QHostInfo::fromName(ui->serverAddress_lineEdit->text());

    if (hostInfo.addresses().isEmpty())
    {
        clientRegistered(false);
        return;
    }

    QHostAddress serverAddress(hostInfo.addresses().first());

    quint16 serverTcpPort(ui->serverTcpPort_spinBox->value());

    ui->startClient_pushButton->setEnabled(false);

    if (m_dataBusClient.start(serverAddress,
                              serverTcpPort,
                              clientId,
                              clientName,
                              activityTimeout,
                              pingResponseTimeout,
                              pingRetryCount) == false)
    {
        clientRegistered(false);
        return;
    }
}

void MainWindow::stopClient()
{
    m_dataBusClient.stop();
}

void MainWindow::clientRegistered(bool status)
{
    if (status)
    {
        ui->startClient_pushButton->setEnabled(false);
        ui->stopClient_pushButton->setEnabled(true);
    }
    else
    {
        ui->startClient_pushButton->setEnabled(true);
        ui->stopClient_pushButton->setEnabled(false);
    }
}

void MainWindow::clientStopped()
{
    ui->startClient_pushButton->setEnabled(true);
    ui->stopClient_pushButton->setEnabled(false);
}

void MainWindow::processReceivedPacket(DataBus::Packet packet)
{
    // Process packet
    switch (packet.getPacketType())
    {
        case DataBus::PacketType_GetClientListResponse:
        {
            // Check payload
            if ((packet.getSource() != 0) ||
                (packet.getDestination() != m_dataBusClient.getClientId()))
            {
                // Error, invalid source and/or destination
                break;
            }

            // Parse payload
            QList<quint8> clientIdList;

            if (DataBus::GetClientListResponsePacket::parse(packet,
                                                            &clientIdList) == false)
            {
                // Error, failed to parse payload
                break;
            }

            // Save the client list to a model
            m_registeredClientIdListModel.setClients(clientIdList);
            break;
        }

        case DataBus::PacketType_GetClientNameResponse:
        {
            // Check payload
            if ((packet.getSource() == 0) ||
                (packet.getDestination() != m_dataBusClient.getClientId()))
            {
                // Error, invalid source and/or destination
                break;
            }

            // Parse payload
            QString clientName;

            if (DataBus::GetClientNameResponsePacket::parse(packet,
                                                            &clientName) == false)
            {
                // Error, failed to parse payload
                break;
            }

            m_selectedClientName = clientName;

            // Display client name
            ui->registeredClientInfo_plainTextEdit->appendPlainText(QLatin1String("Client Name: ") +
                                                                    clientName);

            // Read client status
            m_dataBusClient.sendGetClientStatusRequestPacket(m_selectedClientId);

            break;
        }

        case DataBus::PacketType_GetClientStatusResponse:
        {
            // Check payload
            if ((packet.getSource() != 0) ||
                (packet.getDestination() != m_dataBusClient.getClientId()))
            {
                // Error, invalid source and/or destination
                break;
            }

            // Parse payload
            quint8 clientId;
            DataBus::ClientStatus clientStatus;

            if (DataBus::GetClientStatusResponsePacket::parse(packet,
                                                              &clientId,
                                                              &clientStatus) == false)
            {
                // Error, failed to parse payload
                break;
            }

            QString statusText;

            switch (clientStatus)
            {
                case DataBus::ClientStatus_Active:
                {
                    statusText = QLatin1String("Active");
                    break;
                }

                case DataBus::ClientStatus_Inactive:
                {
                    statusText = QLatin1String("Inactive");
                    break;
                }

                case DataBus::ClientStatus_ErrorUnknownClient:
                {
                    statusText = QLatin1String("Error (Unknown Client)");
                    break;
                }

                default:
                {
                    break;
                }
            }

            if (statusText.isEmpty())
            {
                break;
            }

            m_selectedClientStatus = clientStatus;

            // Display client status
            ui->registeredClientInfo_plainTextEdit->appendPlainText(QLatin1String("Client Status: ") +
                                                                    statusText);

            // Read client property list
            m_dataBusClient.sendGetClientPropertyListRequestPacket(m_selectedClientId);

            break;
        }

        case DataBus::PacketType_GetClientPropertyListResponse:
        {
            // Check payload
            if ((packet.getSource() == 0) ||
                (packet.getDestination() != m_dataBusClient.getClientId()))
            {
                // Error, invalid source and/or destination
                break;
            }

            // Parse payload
            if (DataBus::GetClientPropertyListResponsePacket::parse(packet,
                                                                    &m_pendingPropertyIdList) == false)
            {
                // Error, failed to parse payload
                break;
            }

            // TODO: implement real property list
            QString text;

            for (int i = 0; i < m_pendingPropertyIdList.size(); i++)
            {
                text.append(QString::number(m_pendingPropertyIdList.at(i)) + QLatin1String(" "));
            }

            // Display client status
            ui->registeredClientInfo_plainTextEdit->appendPlainText(QLatin1String("Client Property List: ") +
                                                                    text);

            // Start reading client property info for first property
            if (m_pendingPropertyIdList.isEmpty() == false)
            {
                m_dataBusClient.sendGetClientPropertyInfoRequestPacket(m_selectedClientId,
                                                                       m_pendingPropertyIdList.takeFirst());
            }

            break;
        }

        case DataBus::PacketType_GetClientPropertyInfoResponse:
        {
            // Check payload
            if ((packet.getSource() == 0) ||
                (packet.getDestination() != m_dataBusClient.getClientId()))
            {
                // Error, invalid source and/or destination
                break;
            }

            // Parse payload
            DataBus::PropertyInfo propertyInfo;

            if (DataBus::GetClientPropertyInfoResponsePacket::parse(packet,
                                                                    &propertyInfo) == false)
            {
                // Error, failed to parse payload
                break;
            }

            if (propertyInfo.isValid() == false)
            {
                // Error, failed to parse payload
                break;
            }

            QString text = QLatin1String("\t"
                                         "Id: %1    "
                                         "Data Type: \"%2\"    "
                                         "Access Permission: \"%3\"    "
                                         "Name: \"%4\"    ");

            text = text.arg(QString::number(propertyInfo.getId()),
                            QString::number(propertyInfo.getDataType()),
                            QString::number(propertyInfo.getAccessPermission()),
                            propertyInfo.getName());

            // Display client status
            ui->registeredClientInfo_plainTextEdit->appendPlainText(text);

            // Start reading client property info for first property
            if (m_pendingPropertyIdList.isEmpty() == false)
            {
                m_dataBusClient.sendGetClientPropertyInfoRequestPacket(m_selectedClientId,
                                                                       m_pendingPropertyIdList.takeFirst());
            }
            else
            {
                // TODO: get method list
            }

            break;
        }

        default:
        {
            // Error, unexpected packet
            break;
        }
    }
}

void MainWindow::readClientList()
{
    // First remove all clients from the model
    m_registeredClientIdListModel.removeAllClients();

    // Send command to get client list from the server and wait for the response
    m_dataBusClient.sendGetClientListRequestPacket();
}

void MainWindow::readClientInfo()
{
    // Clear client info
    ui->registeredClientInfo_plainTextEdit->clear();

    // Check if client is registered
    if (m_dataBusClient.isRegistered() == false)
    {
        // Error, client has to be registered first
        return;
    }

    // Get selected Client ID
    QModelIndex selectedIndex = ui->registeredClients_listView->currentIndex();

    quint8 selectedClientId = m_registeredClientIdListModel.getClientId(selectedIndex.row());

    if ((selectedClientId == 0) ||
        (selectedClientId == m_dataBusClient.getClientId()))
    {
        // Error, invalid Client ID
        return;
    }

    m_selectedClientId = selectedClientId;

    ui->registeredClientInfo_plainTextEdit->appendPlainText(QLatin1String("Client ID: ") +
                                                            QString::number(selectedClientId));

    // Start reading client info
    m_dataBusClient.sendGetClientNameRequestPacket(selectedClientId);
}
